package com.ninth_group.dao.Impl;


import com.ninth_group.constant.UserConstants;
import com.ninth_group.dao.UserDao;
import com.ninth_group.dto.UserDTO;
import com.ninth_group.exception.user.PSValidException;
import com.ninth_group.exception.user.UsernameException;
import com.ninth_group.po.User;
import com.ninth_group.utils.HBaseServiceUtil;
import com.ninth_group.utils.HiveUtil;
import com.ninth_group.utils.JWTUtil;
import com.ninth_group.utils.RedisSerializerUtil;
import com.ninth_group.vo.UserInfoVO;
import com.ninth_group.vo.UserVO;
import jakarta.annotation.Resource;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Repository
public class UserDaoImpl implements UserDao {
    @Resource
    private HiveUtil hiveUtil;
    @Resource
    private HBaseServiceUtil hBaseService;
    @Resource
    private RedisSerializerUtil redisUtil;
    private static final String QUERY_SQL = "SELECT * FROM `user` WHERE username = ?";
    private static final String INSERT_SQL =
            "INSERT INTO `user` (id, username, password) VALUES (?, ?, ?)";
    private static final String USERNAME = "username";
    private static final String PASSWORD = "password";
    private static final String HBASE_TABEL_NAME = "user";
    private static final String[] COLUMNS = {"username", "password"};
    private static final String PS_ERR = "0";
    private static final String LOGIN_SUCCESS = "1";
    // 注册后登录
    private static final String REGISTER_SUCCESS = "2";

    /**
     * 登录 -- 数据存在hbase
     * @param userDTO 用户信息
     * @return 该列表存储状态和token, 1 登录, 0 密码错误, 2 注册
     */
    @Override
    public List<String> login(UserDTO userDTO) throws Exception {
        List<String> result = new ArrayList<>(2);
        String username = userDTO.getUsername();
        String password = userDTO.getPassword();

        // 查询redis缓存
        UserVO userVo = redisUtil.get(UserConstants.USER_INFO + username, UserVO.class);

        // 存在用户信息, 登录未过期
        if (userVo != null && userVo.getUsername().equals(username)) {
            result.add(LOGIN_SUCCESS);
            result.add(userVo.getToken());
            // 刷新用户过期时间
            redisUtil.set(UserConstants.USER_INFO + username, userVo,
                    UserConstants.CACHE_TIME, TimeUnit.MINUTES);
            return result;
        }

        // 获取所有用户信息
        Map<String, Map<String, String>> userMap =
                hBaseService.getResultScanner(HBASE_TABEL_NAME);

        // 判断用户是否存在
        String loginResult = userIsExist(userMap, username, password);

        if (LOGIN_SUCCESS.equals(loginResult)) {
            String token = JWTUtil.getToken(Map.of(USERNAME, username));
            result.add(LOGIN_SUCCESS);
            result.add(token);
        } else if (PS_ERR.equals(loginResult)) {
            result.add(PS_ERR);
            result.add(null);
        } else if (REGISTER_SUCCESS.equals(loginResult)) {
            // 注册后再次尝试登录，确保用户已写入 HBase
            String token = JWTUtil.getToken(Map.of(USERNAME, username));
            result.add(REGISTER_SUCCESS);
            result.add(token);
        }
        UserVO res = new UserVO(username, result.get(1));

        // 将用户信息写入redis缓存
        redisUtil.set(UserConstants.USER_INFO + username, res,
                UserConstants.CACHE_TIME, TimeUnit.MINUTES);
        return result;
    }

    // 判断用户是否存在
    public String userIsExist(Map<String, Map<String,String>> user, String username, String password) throws IOException {
        for (Map<String, String> value : user.values()) {
            // 判断用户是否存在
            if (value.get(USERNAME).equals(username))
                // 判断密码
                return isCorrect(value.get(PASSWORD), password) ? LOGIN_SUCCESS : PS_ERR;
        }
        // 注册用户并登录
        Long id = hBaseService.generateUserId();
        registerToHbase(id, username, password);
        return REGISTER_SUCCESS;
    }

    public void registerToHbase(Long id, String username, String password) {
        String ps = BCrypt.hashpw(password, BCrypt.gensalt());
        String[] values = {username, ps};
        hBaseService.putData(HBASE_TABEL_NAME, id + "", "info", COLUMNS, values);
    }

    /* 登录 -- 数据存在hive
    public List<String> login(UserDTO userDTO) throws Exception {
        // 预定义返回结果
        List<String> result = new ArrayList<>(2);
        String token = "";

        // 1. 获取账号密码信息
        String username = userDTO.getUsername();
        String password = userDTO.getPassword();

        // 2. 查询hive用户信息  用户名唯一, 查询结果必定只有一个或没有
        List<User> users = hiveUtil.executeQuery(QUERY_SQL, rs -> {
            try {
                return User.mapRow(rs);
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        },  username);
        // 3.1 若查询结果为空, 返回空对象
        User user = users.isEmpty() ? null : users.getFirst();

        // 4. 判断信息是否一致
        if (user != null) {
            if (isCorrect(user, password)) {
                // 4.1 匹配成功, 封装JWT令牌信息并返回
                token = JWTUtil.getToken(Map.of(USERNAME, user.getUsername(),
                        "password", user.getPassword()));
                Collections.addAll(result, "1", token);
            } else {
                Collections.addAll(result, "0", "");
            }
            return result;
        }
        User registerUser = new User(username, password);
        // 4.2 注册新用户
        int maxId = getMaxId();
        register(maxId + 1, username, password);

        // 4.3 封装JWT令牌信息并返回
        token = JWTUtil.getToken(Map.of(USERNAME, registerUser.getUsername(),
                "password", registerUser.getPassword()));
        Collections.addAll(result, "2", token);
        return result;
    }*/

    /**
     * 判断密码是否正确
     * @param user 数据库中的用户信息
     * @param password 用户输入的密码
     * @return t/f
     */
    private boolean isCorrect(User user, String password) {
        return BCrypt.checkpw(password, user.getPassword());
    }
    private boolean isCorrect(String oldPw, String newPw) {
        return BCrypt.checkpw(newPw, oldPw);
    }


    /**
     * 注册新用户
     * @param username 用户名
     * @param password 密码
     */
    private void registerToHive(Integer id, String username, String password) {
        if (username == null || username.isEmpty())
            throw new UsernameException("用户名不能为空");

        if (!isValidPassword(password))
            throw new PSValidException("密码长度在 6~10 之间, 只允许 a-z, A-Z, 0-9, _, $");

        String ps = BCrypt.hashpw(password, BCrypt.gensalt());
        hiveUtil.executeUpdate(INSERT_SQL, id, username, ps);
    }

    /**
     * 检查密码是否符合要求
     * @param password 密码
     * @return t/f
     */
    private boolean isValidPassword(String password) {
        if (password == null) return false;

        // 检查长度是否在 6~10 之间
        if (password.length() < 6 || password.length() > 10) {
            return false;
        }

        // 正则表达式匹配：只允许 a-z, A-Z, 0-9, _, $
        String regex = "^[a-zA-Z0-9_$]{6,10}$";
        return password.matches(regex);
    }

    /**
     * hive不支持id自动递增, 所以这里手动获取最大id
     * @return id
     * @throws SQLException 抛出异常
     */
    private int getMaxId() throws SQLException {
        String sql = "SELECT COALESCE(MAX(id), 0) FROM `user`";
        return hiveUtil.queryForInt(sql);
    }
}
